Clean up segment selector fixup and validation.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 23 Feb 2006 13:43:45 +0000 (14:43 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 23 Feb 2006 13:43:45 +0000 (14:43 +0100)
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/domain.c
xen/arch/x86/traps.c
xen/arch/x86/x86_32/mm.c
xen/arch/x86/x86_32/traps.c
xen/arch/x86/x86_64/mm.c
xen/common/elf.c
xen/include/asm-x86/desc.h

index 21ef47f0ce79e226c176a86a3305776a19a2727c..ee0bada316e57e194a4471a6f4d18247be58f35d 100644 (file)
@@ -349,27 +349,19 @@ int arch_set_info_guest(
     unsigned long phys_basetab = INVALID_MFN;
     int i, rc;
 
-    /*
-     * This is sufficient! If the descriptor DPL differs from CS RPL then we'll
-     * #GP. If DS, ES, FS, GS are DPL 0 then they'll be cleared automatically.
-     * If SS RPL or DPL differs from CS RPL then we'll #GP.
-     */
     if ( !(c->flags & VGCF_HVM_GUEST) )
     {
-        if ( !VALID_STACKSEL(c->user_regs.ss) ||
-             !VALID_STACKSEL(c->kernel_ss) ||
-             !VALID_CODESEL(c->user_regs.cs) )
-            return -EINVAL;
+        fixup_guest_selector(c->user_regs.ss);
+        fixup_guest_selector(c->kernel_ss);
+        fixup_guest_selector(c->user_regs.cs);
 
 #ifdef __i386__
-        if ( !VALID_CODESEL(c->event_callback_cs) ||
-             !VALID_CODESEL(c->failsafe_callback_cs) )
-            return -EINVAL;
+        fixup_guest_selector(c->event_callback_cs);
+        fixup_guest_selector(c->failsafe_callback_cs);
 #endif
 
         for ( i = 0; i < 256; i++ )
-            if ( !VALID_CODESEL(c->trap_ctxt[i].cs) )
-                return -EINVAL;
+            fixup_guest_selector(c->trap_ctxt[i].cs);
     }
     else if ( !hvm_enabled )
       return -EINVAL;
@@ -383,6 +375,7 @@ int arch_set_info_guest(
         v->arch.flags |= TF_kernel_mode;
 
     memcpy(&v->arch.guest_context, c, sizeof(*c));
+    init_int80_direct_trap(v);
 
     if ( !(c->flags & VGCF_HVM_GUEST) )
     {
index a9a0ff10b2453c8514147c1fc52f9f9cfc767a3a..d331d7d72a6c95c24874f415b11fc926b9024fd5 100644 (file)
@@ -1430,11 +1430,7 @@ long do_set_trap_table(struct trap_info *traps)
         if ( cur.address == 0 )
             break;
 
-        if ( !VALID_CODESEL(cur.cs) )
-        {
-            rc = -EPERM;
-            break;
-        }
+        fixup_guest_selector(cur.cs);
 
         memcpy(&dst[cur.vector], &cur, sizeof(cur));
 
index 2bcb57f8b4e87fc8ece193293321b0ba2b796c31..f622498922ed4e65dacd2d870199e053fa6f4e22 100644 (file)
@@ -223,8 +223,7 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
     int nr = smp_processor_id();
     struct tss_struct *t = &init_tss[nr];
 
-    if ( !VALID_STACKSEL(ss) )
-        return -EPERM;
+    fixup_guest_selector(ss);
 
     current->arch.guest_context.kernel_ss = ss;
     current->arch.guest_context.kernel_sp = esp;
@@ -239,7 +238,7 @@ int check_descriptor(struct desc_struct *d)
 {
     unsigned long base, limit;
     u32 a = d->a, b = d->b;
-    u16 cs = a>>16;
+    u16 cs;
 
     /* A not-present descriptor will always fault, so is safe. */
     if ( !(b & _SEGMENT_P) ) 
@@ -272,17 +271,12 @@ int check_descriptor(struct desc_struct *d)
         if ( (b & _SEGMENT_TYPE) != 0xc00 )
             goto bad;
 
-        /* Can't allow far jump to a Xen-private segment. */
-        if ( !VALID_CODESEL(cs) )
+        /* Validate and fix up the target code selector. */
+        cs = a >> 16;
+        fixup_guest_selector(cs);
+        if ( !guest_gate_selector_okay(cs) )
             goto bad;
-
-        /*
-         * VALID_CODESEL might have fixed up the RPL for us. So be sure to
-         * update the descriptor.
-         *
-         */
-        d->a &= 0x0000ffff;
-        d->a |= cs<<16;
+        a = d->a = (d->a & 0xffffU) | (cs << 16);
 
         /* Reserved bits must be zero. */
         if ( (b & 0xe0) != 0 )
index 5d23bea5942b10399c646c5cb7d067a11f497a74..51c8e9b7debefc7d9ebeb4b5e93416c7a45d09d2 100644 (file)
@@ -254,10 +254,14 @@ void init_int80_direct_trap(struct vcpu *v)
 
     /*
      * We can't virtualise interrupt gates, as there's no way to get
-     * the CPU to automatically clear the events_mask variable.
+     * the CPU to automatically clear the events_mask variable. Also we
+     * must ensure that the CS is safe to poke into an interrupt gate.
      */
-    if ( TI_GET_IF(ti) )
+    if ( TI_GET_IF(ti) || !guest_gate_selector_okay(ti->cs) )
+    {
+        v->arch.int80_desc.a = v->arch.int80_desc.b = 0;
         return;
+    }
 
     v->arch.int80_desc.a = (ti->cs << 16) | (ti->address & 0xffff);
     v->arch.int80_desc.b =
@@ -274,8 +278,8 @@ long do_set_callbacks(unsigned long event_selector,
 {
     struct vcpu *d = current;
 
-    if ( !VALID_CODESEL(event_selector) || !VALID_CODESEL(failsafe_selector) )
-        return -EPERM;
+    fixup_guest_selector(event_selector);
+    fixup_guest_selector(failsafe_selector);
 
     d->arch.guest_context.event_callback_cs     = event_selector;
     d->arch.guest_context.event_callback_eip    = event_address;
index f783cce7e6eea846124e9b0b61ed89741db82c76..ee45c2a875fdec4ec8bde95da82398d5dfaac2a5 100644 (file)
@@ -292,7 +292,7 @@ long do_set_segment_base(unsigned int which, unsigned long base)
 int check_descriptor(struct desc_struct *d)
 {
     u32 a = d->a, b = d->b;
-    u16 cs = a>>16;
+    u16 cs;
 
     /* A not-present descriptor will always fault, so is safe. */
     if ( !(b & _SEGMENT_P) ) 
@@ -314,17 +314,12 @@ int check_descriptor(struct desc_struct *d)
     if ( (b & _SEGMENT_TYPE) != 0xc00 )
         goto bad;
 
-    /* Can't allow far jump to a Xen-private segment. */
-    if ( !VALID_CODESEL(cs) )
+    /* Validate and fix up the target code selector. */
+    cs = a >> 16;
+    fixup_guest_selector(cs);
+    if ( !guest_gate_selector_okay(cs) )
         goto bad;
-
-    /*
-     * VALID_CODESEL might have fixed up the RPL for us. So be sure to
-     * update the descriptor.
-     *
-     */
-    d->a &= 0x0000ffff;
-    d->a |= cs<<16;
+    a = d->a = (d->a & 0xffffU) | (cs << 16);
 
     /* Reserved bits must be zero. */
     if ( (b & 0xe0) != 0 )
index 4fc8f26ecd6726c21dfa9885d4fd780d33dfbdde..412acae01aa21c82f0004bc8226de6a57afa73ae 100644 (file)
@@ -61,7 +61,6 @@ int parseelfimage(struct domain_setup_info *dsi)
             continue;
 
         guestinfo = elfbase + shdr->sh_offset;
-        printk("Xen-ELF header found: '%s'\n", guestinfo);
 
         if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
              (strstr(guestinfo, "GUEST_OS=linux") == NULL) )
index 793413f56acc328364718f1b316969c222d2e652..7208c04ce091be61dad8dda6c63e1a01fe6309c5 100644 (file)
 #define GUEST_KERNEL_RPL 1
 #endif
 
+/* Fix up the RPL of a guest segment selector. */
+#define fixup_guest_selector(sel)                               \
+    ((sel) = (((sel) & 3) >= GUEST_KERNEL_RPL) ? (sel) :        \
+     (((sel) & ~3) | GUEST_KERNEL_RPL))
+
 /*
- * Guest OS must provide its own code selectors, or use the one we provide. Any
- * LDT selector value is okay. Note that checking only the RPL is insufficient:
- * if the selector is poked into an interrupt, trap or call gate then the RPL
- * is ignored when the gate is accessed.
+ * We need this function because enforcing the correct guest kernel RPL is
+ * unsufficient if the selector is poked into an interrupt, trap or call gate.
+ * The selector RPL is ignored when a gate is accessed. We must therefore make
+ * sure that the selector does not reference a Xen-private segment.
+ * 
+ * Note that selectors used only by IRET do not need to be checked. If the
+ * descriptor DPL fiffers from CS RPL then we'll #GP.
+ * 
+ * Stack and data selectors do not need to be checked. If DS, ES, FS, GS are
+ * DPL < CPL then they'll be cleared automatically. If SS RPL or DPL differs
+ * from CS RPL then we'll #GP.
  */
-#define VALID_SEL(_s)                                                      \
-    (((((_s)>>3) < FIRST_RESERVED_GDT_ENTRY) || ((_s)&4)) &&               \
-     (((_s)&3) == GUEST_KERNEL_RPL))
-#define VALID_CODESEL(_s) ({                                               \
-    if ( ((_s) & 3) == 0 )                                                 \
-        (_s) |= GUEST_KERNEL_RPL;                                          \
-    (_s) == FLAT_KERNEL_CS || VALID_SEL(_s); })
-#define VALID_STACKSEL(_s) ({                                              \
-    if ( ((_s) & 3) == 0 )                                                 \
-        (_s) |= GUEST_KERNEL_RPL;                                          \
-    (_s) == FLAT_KERNEL_SS || VALID_SEL(_s); })
+#define guest_gate_selector_okay(sel)                                   \
+    ((((sel)>>3) < FIRST_RESERVED_GDT_ENTRY) || /* Guest seg? */        \
+     ((sel) == FLAT_KERNEL_CS) ||               /* Xen default seg? */  \
+     ((sel) & 4))                               /* LDT seg? */
 
 /* These are bitmasks for the high 32 bits of a descriptor table entry. */
 #define _SEGMENT_TYPE    (15<< 8)